package com.zengqingfa.examples.mybatisplus.interceptor;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.zengqingfa.examples.mybatisplus.annotation.FieldPermission2;
import com.zengqingfa.examples.mybatisplus.dto.DynamicColumnInfoDTO;
import com.zengqingfa.examples.mybatisplus.enums.DynamicColumnModuleEnum;
import com.zengqingfa.examples.mybatisplus.service.IDynamicColumnService;
import com.zengqingfa.examples.mybatisplus.util.StringToDateConverter;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zengqingfa
 * @className FieldAuthInterceptor2
 * @description 字段权限拦截器
 * @create 2022/12/17 16:09
 * https://www.cnblogs.com/zxjest/p/13973351.html
 */
@Component
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class FieldAuthInterceptor2 implements Interceptor {


    @Resource
    private IDynamicColumnService dynamicColumnService;

    // //这里是每次执行操作的时候，都会进行这个拦截器的方法内
    public Object intercept(Invocation invocation) throws Throwable {
        List resList = new ArrayList();
        DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) invocation.getTarget();
        MetaObject metaStatementHandler = SystemMetaObject.forObject(defaultResultSetHandler);
        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("mappedStatement");
        String id = mappedStatement.getId();
        // 通过类全路径获取Class对象
        Class<?> classType = Class.forName(id.substring(0, id.lastIndexOf(".")));
        // 获取当前所拦截的方法名称
        String mName = id.substring(id.lastIndexOf(".") + 1);
        List<DynamicColumnInfoDTO> columnInfos = Lists.newArrayList();
        // 遍历类中所有方法名称，并if匹配上当前所拦截的方法
        for (Method method : classType.getDeclaredMethods()) {
            if (mName.equals(method.getName())) {
                // 判断方法上是否带有自定义@FieldPermission注解
                FieldPermission2 interceptorAnnotation = method.getAnnotation(FieldPermission2.class);
                // 获取到当前用户，可以通过ThreadLocal中获取，这里从请求头获取
                //获取到请求的request,
                HttpServletRequest request =
                        ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
                String userCode = request.getHeader("userCode");
                if (interceptorAnnotation == null || StringUtils.isBlank(userCode)) {
                    return invocation.proceed();
                }
                //获取到当前用户拥有的字段,没有则默认字段
                columnInfos = dynamicColumnService.queryDynamicColumn(DynamicColumnModuleEnum.USER.getType(), userCode);
            }
        }
        if (CollectionUtil.isEmpty(columnInfos)) {
            return invocation.proceed();
        }
        //获取到列名
        List<String> columns = columnInfos.stream().map(DynamicColumnInfoDTO::getField).distinct().collect(Collectors.toList());
        //获取节点属性的集合
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        Class<?> resultType = resultMaps.get(0).getType();
        //获取mybatis返回的实体类类型名
        int resultMapCount = resultMaps.size();
        if (resultMapCount > 0) {
            Statement statement = (Statement) invocation.getArgs()[0];
            ResultSet resultSet = statement.getResultSet();
            if (resultSet != null) {
                //获得对应列名
                ResultSetMetaData rsmd = resultSet.getMetaData();
                List<String> columnList = new ArrayList<>();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    //转换为驼峰命名，通过此字段获取到值
                    String s = StrUtil.toCamelCase(rsmd.getColumnName(i));
                    columnList.add(s);
                }
                while (resultSet.next()) {
                    LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();
                    for (String colName : columnList) {
                        //如果有权限，则把字段加入到结果集中
                        if (columns.contains(colName)) {
                            resultMap.put(colName, resultSet.getString(colName));
                        }
                    }
                    Object o = resultType.newInstance();
                    //是日期的需要写明格式
                    ConvertUtils.register(new StringToDateConverter(), Date.class);
                    BeanUtilsBean.getInstance().populate(o, resultMap);
                    //将转换后的map转换为实体类中
//                    BeanUtils.populate(o, resultMap);
                    resList.add(o);
                }
                return resList;
            }
        }
        return invocation.proceed();
    }

    /**
     * //主要是为了把这个拦截器生成一个代理放到拦截器链中
     * ^Description包装目标对象 为目标对象创建代理对象
     *
     * @Param target为要拦截的对象
     * @Return代理对象
     */
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {

    }
}